use std::{
    collections::HashMap, fs, net::TcpStream, path::{Path, PathBuf}
};

use crate::{
    InfoResponse, ResponseCode,
    auth::{self},
};
use actix_web::{get, post, web, ResponseError};
use base64::prelude::BASE64_STANDARD;
use base64::prelude::*;
use local_ip_address::local_ip;
use rsa::{RsaPrivateKey, pkcs8::DecodePrivateKey};
use serde::{Deserialize, Serialize};
use ssh2::{Error, ErrorCode, Session};
use std::io::prelude::*;
use sysinfo::System;

const FOR_PROJ: &str = "dataxone";
// 查询系统规格
const SYS_SIZE_CMD: &str = "LANG=C lscpu | grep '^CPU(s):' | awk '{printf(\"%.0fc\",$2)}' ; cat /proc/meminfo | grep MemTotal | awk '{printf(\"%.0fg\n\", $2/1024/1024)}'";
const SYS_PRETTY_NAME: &str = "eval \"$(grep '^PRETTY_NAME' /etc/os-release)\" | echo $PRETTY_NAME";
const SSH_DEFAULT_PORT: &str = "22";

#[derive(Debug, Serialize, Deserialize)]
pub struct HostInfo {
    ip: String,
    localip: Option<String>,
    size: Option<String>,
    username: String,
    port: Option<String>,
    os: Option<String>,
    #[serde(skip_serializing)]
    password: String,
    group: Option<String>,
}

fn get_config_home() -> PathBuf {
    let user_home = env!("HOME");
    Path::new(user_home).join(format!(".{}", FOR_PROJ))
}

pub fn connect_ssh(
    connect_strings: String,
    username: String,
    password: String,
) -> Result<Session, String> {
    // 新建连接
    let tcp = match TcpStream::connect(connect_strings) {
        Ok(tcp) => tcp,
        Err(e) => {
            // 无法链接到对应的端口
            // eprintln!(
            //     "Host: {}, Session create failed, Cause: {}",
            //     connect_strings, e
            // );
            return Err(format!("SSH Session create failed, Cause: {}", e.kind().to_string()));
        }
    };
    let mut sess = Session::new().unwrap();
    sess.set_tcp_stream(tcp);
    match sess.handshake() {
        Ok(()) => {}
        Err(e) => {
            // eprintln!(
            //     "Host: {}, Server handshake failed, cause: {}",
            //     connect_strings, e
            // );
            return Err(format!("SSH handshake failed, cause: {}", e.message().to_owned()));
        }
    }
    let pwd = &password.clone();
    match sess.userauth_password(&username, pwd) {
        Ok(()) => {}
        Err(e) => {
            return Err(format!("Connection not established, cause: {}", e.message().to_owned()));
        }
    }
    // sess.set_keepalive(true, SSH_KEEPALIVE_INTERVAL as u32);
    Ok(sess)
}

// 执行远程命令
pub fn exec_cmd(sess: &Session, cmd: &str) -> (i32, String) {
    let mut channel = sess.channel_session().unwrap();
    channel.exec(&cmd).unwrap();

    let mut stdout = String::new();
    channel.read_to_string(&mut stdout).unwrap();
    let mut stderr: String = String::new();
    channel.stderr().read_to_string(&mut stderr).unwrap();

    channel.wait_close().unwrap();
    // println!("before.info1: cmd: `{}`", &cmd);
    let status = channel.exit_status().unwrap();
    if status == 0 {
        (
            channel.exit_status().unwrap(),
            stdout.trim_end_matches("\n").to_owned(),
        )
    } else {
        (
            channel.exit_status().unwrap(),
            stderr.trim_end_matches("\n").to_owned(),
        )
    }
}
#[get("/test")]
pub async fn test(params: web::Json<HostInfo>) -> web::Json<InfoResponse<Option<String>>> {

    // 通过密钥解密
    let ciphertext = BASE64_STANDARD.decode(params.password.clone()).unwrap();
    let pkcs8 = include_str!("../key/private_key_pkcs8.pem");
    let private_key = RsaPrivateKey::from_pkcs8_pem(&pkcs8).unwrap();

    let client_raw = match private_key.decrypt(rsa::pkcs1v15::Pkcs1v15Encrypt, &ciphertext) {
        Err(e) => {
            return web::Json(InfoResponse {
                message: format!("Password {e}"),
                code: ResponseCode::Failed,
                data: None,
            });
        }
        Ok(client_raw) => client_raw,
    };

    let ssh_port = params.port.clone().unwrap_or(SSH_DEFAULT_PORT.to_owned());
    let password_plain_text = String::from_utf8_lossy(&client_raw).to_string();
    match connect_ssh(
        format!("{}:{}", params.ip, ssh_port),
        params.username.clone(),
        password_plain_text.clone(),
    ) {
        Err(e) => return web::Json(InfoResponse {
            message: e,
            code: ResponseCode::Failed,
            data: None,
        }),

        Ok(_sess) =>  return web::Json(InfoResponse {
            message: "Success".to_owned(),
            code: ResponseCode::Success,
            data: None,
        })
    };

    
}

// 由于所有信息存在文件，因此没有查询的功能
#[get("/list")]
pub async fn list() -> web::Json<InfoResponse<Vec<HostInfo>>> {
    let config_home = get_config_home();

    let config_hosts = config_home.join("hosts");
    // $ARGV_PARAM_DATAXONE_INSTALL_DIR:$ARGV_PARAM_DATAXONE_PORTAL:$ARGV_PARAM_OS_CURRENT_IP:$ARGV_PARAM_OS_IPS
    let config_version = config_home.join("version");
    // $ARGV_PARAM_OS_USER:$ARGV_PARAM_DATAXONE_INSTALL_DIR:$(getVersion):$ARGV_PARAM_DATAXONE_INSTALL_VERSION:$ARGV_PARAM_DATAXONE_INSTALL_MODE:N
    let config_apps = config_home.join("apps");
    let config_webapps = config_home.join("webapps");
    let config_zk = config_home.join("zk");

    let mut data = Vec::new();
    let sys = System::new_all();
    // 本机自动添加
    let my_local_ip = local_ip();
    if let Ok(my_local_ip) = my_local_ip {
        data.push(HostInfo {
            ip: my_local_ip.to_string(),
            localip: Some(my_local_ip.to_string()),
            size: Some(format!(
                "{}c{}g/{}m",
                sys.cpus().len(),
                (sys.total_memory() as f64 / 1024.0 / 1024.0 / 1024.0).round(),
                (sys.available_memory() as f64 / 1024.0 / 1024.0).round()
            )),
            username: env!("USER").to_string(),
            port: None,
            os: Some(format!(
                "{} {} Version {} Kernel Version {}",
                System::name().unwrap_or_default(),
                System::host_name().unwrap_or_default(),
                System::os_version().unwrap_or_default(),
                System::kernel_version().unwrap_or_default()
            )),
            password: String::new(),
            group: None,
        });
    } else {
        log::warn!("Error getting local IP: {:?}", my_local_ip);
    }

    web::Json(InfoResponse {
        message: "Success".to_owned(),
        code: ResponseCode::Success,
        data: Some(data),
    })
}

#[post("/add")]
pub async fn add(
    mut params: web::Json<HostInfo>,
) -> web::Json<InfoResponse<HashMap<String, String>>> {
    // 通过密钥解密
    let ciphertext = BASE64_STANDARD.decode(params.password.clone()).unwrap();
    let pkcs8 = include_str!("../key/private_key_pkcs8.pem");
    let private_key = RsaPrivateKey::from_pkcs8_pem(&pkcs8).unwrap();

    let client_raw = match private_key.decrypt(rsa::pkcs1v15::Pkcs1v15Encrypt, &ciphertext) {
        Err(e) => {
            return web::Json(InfoResponse {
                message: format!("Password {e}"),
                code: ResponseCode::Failed,
                data: None,
            });
        }
        Ok(client_raw) => client_raw,
    };

    let ssh_port = params.port.clone().unwrap_or(SSH_DEFAULT_PORT.to_owned());
    let password_plain_text = String::from_utf8_lossy(&client_raw).to_string();
    let ssh_session = match connect_ssh(
        format!("{}:{}", params.ip, ssh_port),
        params.username.clone(),
        password_plain_text.clone(),
    ) {
        Err(e) => {
            return web::Json(InfoResponse {
                message: e,
                code: ResponseCode::Failed,
                data: None,
            });
        }
        Ok(sess) => sess,
    };

    // 查询系统信息
    let (status_code, stdout) = exec_cmd(&ssh_session, SYS_SIZE_CMD);
    if status_code == 0 {
        params.size = Some(stdout);
    } else {
        // 命令执行失败
        log::error!(
            "{}, status_code: {}, stderr: {}",
            params.ip,
            status_code,
            stdout
        );
        params.size = None;
    }

    // 获取系统版本
    let (status_code, stdout) = exec_cmd(&ssh_session, SYS_PRETTY_NAME);
    if status_code == 0 {
        params.os = Some(stdout);
    } else {
        // 命令执行失败
        log::error!(
            "{}, status_code: {}, stderr: {}",
            params.ip,
            status_code,
            stdout
        );
        params.os = None;
    }

    let sm4_password = match auth::encrypt(
        auth::SM4_IV.to_owned(),
        auth::SM4_IV.to_owned(),
        password_plain_text,
    ) {
        Ok(en) => BASE64_STANDARD.encode(en),
        Err(e) => {
            return web::Json(InfoResponse {
                message: format!("{e}"),
                code: ResponseCode::Failed,
                data: None,
            });
        }
    };

    // 写入文件
    let config_home = get_config_home();
    let config_hosts = config_home.join("xhosts");
    // $ARGV_PARAM_DATAXONE_INSTALL_DIR:$ARGV_PARAM_DATAXONE_PORTAL:$ARGV_PARAM_OS_CURRENT_IP:$ARGV_PARAM_OS_IPS

    // 写本地文件
    // ~/.dataxone/xhosts
    let content = match std::fs::read_to_string(&config_hosts) {
        Ok(content) => content,
        Err(e) => {
            return web::Json(InfoResponse {
                message: format!("{e}"),
                code: ResponseCode::Failed,
                data: None,
            });
        }
    };
    let mut buffer = String::new();
    for line in content.lines() {
        if !line.starts_with(&params.ip) {
            buffer.push_str(line);
            buffer.push('\n');
        }
    }
    let grp = params.group.clone().unwrap_or_default();
    buffer.push_str(&format!(
        "{}:{}:{}:{}:{}\n",
        params.ip, params.username, sm4_password, ssh_port, grp
    ));

    if let Err(e) = fs::write(config_hosts, buffer) {
        return web::Json(InfoResponse {
            message: format!("{e}"),
            code: ResponseCode::Failed,
            data: None,
        });
    }
    // => 192.168.30.11:dataxone:egxE6XNdENi4kRPv6mQUQQ==:22:GRP1
    // => 192.168.30.12:dataxone:egxE6XNdENi4kRPv6mQUQQ==:22:GRP1

    let config_sysinfo = config_home.join("sysinfo");
    // ~/.dataxone/sysinfo
    // 192.168.30.11:Spec:sysinfo
    // 192.168.30.12:Spec:sysinfo
    let content = match std::fs::read_to_string(&config_sysinfo) {
        Ok(content) => content,
        Err(e) => {
            return web::Json(InfoResponse {
                message: format!("{e}"),
                code: ResponseCode::Failed,
                data: None,
            });
        }
    };
    let mut buffer = String::new();
    for line in content.lines() {
        if !line.starts_with(&params.ip) {
            buffer.push_str(line);
            buffer.push('\n');
        }
    }
    buffer.push_str(&format!(
        "{}:{}:{}\n",
        params.ip, params.size.clone().unwrap_or_default(), params.os.clone().unwrap_or_default()
    ));

    if let Err(e) = fs::write(config_sysinfo, buffer) {
        return web::Json(InfoResponse {
            message: format!("{e}"),
            code: ResponseCode::Failed,
            data: None,
        });
    }

    // 测试连接是否能连接成功，如果连接成功，则需要执行命令把具体的想要的内容返回

    web::Json(InfoResponse {
        message: "Success".to_owned(),
        code: ResponseCode::Success,
        data: None,
    })
}
